package domain;

import java.util.*;

import entities.role.Role;

@Deprecated
public class Vertex {

	private final Object f;
	// private HashSet<Edge> visitedInEdges = new HashSet<Edge>();
	private FeatureGraph fg;
	private HashSet<Edge> inedges;
	private HashSet<Edge> outedges;
	// for every vertex, there is an equivalence set, e.g., for vertex f, f=3,
	// f=g, f=k, then {3, g, k}
	private HashSet<Vertex> equivalenceSet;

	public Vertex(Object f, FeatureGraph fg) {
		this.f = f;
		this.fg = fg;
		this.inedges = new HashSet<Edge>();
		this.outedges = new HashSet<Edge>();
		this.equivalenceSet = new HashSet<Vertex>();
		fg.getFVMAP().put(f, this);
	}

	public FeatureGraph getAssociatedFeatureGraph() {
		return this.fg;
	}

	public Object getDomainObject() {
		return this.f;
	}

	public HashSet<Edge> getOutEdges() {
		return this.outedges;
	}

	public HashSet<Edge> getInEdges() {
		return this.inedges;
	}

	@Override
	public String toString() {
		String ret = "";
		if (this.f instanceof Role) {
			Role rr = (Role) f;
			ret += rr.getRoleName();
		} else {
			ret += f.toString();
		}
		return ret;
	}

	/*
	 * f<g, g<=k, k<f is a clash but f=g, g<=f is not! DFS search for clashes.
	 * Note that path only refers to a path with both = and <=. hasLTSign
	 * default: false
	 */
	public boolean computeLTClash(Vertex v) {
		return this.computeLTClash(v, new HashSet<Edge>(), false, false);
	}

	private boolean computeLTClash(Vertex v, HashSet<Edge> visited,
			boolean loop, boolean hasLTSign) {
		// boolean possible = false;
		for (Edge e : v.outedges) {
			Vertex dest = e.dest;
			boolean localLT = hasLTSign;
			// localLT |= e.isLTEdge();
			localLT |= e.isLTEdge();
			if (visited.contains(e)) {
				continue;
			}
			visited.add(e);
			// if found this object and have seen < at least once
			if (dest.equals(this) && localLT) {
				loop |= true;
				return loop;
			} else {
				loop |= computeLTClash(dest, visited, loop, localLT);
			}

		}
		return loop;
	}

	/*
	 * private boolean computeLTClash(Vertex v, HashSet<Vertex> visited, boolean
	 * loop, boolean hasLTSign){ //boolean possible = false; for(Edge
	 * e:v.outedges){ Vertex dest = e.dest; boolean localLT = hasLTSign;
	 * //localLT |= e.isLTEdge(); localLT |= e.isLTEdge();
	 * if(visited.contains(dest)){ continue; } visited.add(dest); //if found
	 * this object and have seen < at least once if(dest.equals(this) &&
	 * localLT){ loop |= true; return loop; }else{ loop |= computeLTClash(dest,
	 * visited, loop, localLT); }
	 * 
	 * } return loop; }
	 */

	public boolean computeEQClash(Vertex v) {
		// first compute to get all eqs
		this.computeEQClash(v, new HashSet<Vertex>(), false, true,
				new Stack<Vertex>());
		// saturations
		boolean changed = true;
		while (changed) {
			HashSet<Vertex> more = new HashSet<Vertex>();
			for (Vertex vv : v.equivalenceSet) {
				if (vv.equivalenceSet.size() > 0) {
					more.addAll(vv.equivalenceSet);
				}
			}
			changed &= !v.equivalenceSet.containsAll(more);
			if (changed) {
				v.equivalenceSet.addAll(more);
			}
		}
		// test if >=2 concrete values occur in this set
		HashSet<String> s = new HashSet<String>();
		for (Vertex vc : v.equivalenceSet) {
			if (vc.f instanceof String) {
				String ss = (String) vc.f;
				ss = ss.trim();
				s.add(ss);
			}
		}
		if (s.size() > 1) {
			return true;
		}
		return false;
	}

	/*
	 * f<=g, g=h and a loop form no clashes, but a set of eq concepts. loop
	 * defaults to false; allEqs defaults to true;
	 */
	private boolean computeEQClash(Vertex v, HashSet<Vertex> visited,
			boolean loop, boolean allEqs, Stack<Vertex> path) {
		// System.out.println("For Vertex:"+v.renderDomainObject()+", Objective: "+this.renderDomainObject());
		// Stack<Vertex> localpath = new Stack<Vertex>();
		// localpath.addAll(path);
		// boolean anyloop = false;
		for (Edge e : v.outedges) {
			// System.out.println("Now testing:"+e.toString());
			if (e.isLTEdge()) {
				// only EQ LTEQ edges considered
				continue;
			}
			boolean localEQ = allEqs;
			localEQ &= e.isEqEdge();
			// System.out.println("All EQs:"+allEqs);
			Vertex dest = e.dest;
			if (visited.contains(dest)) {
				continue;
			}
			visited.add(dest);
			if (localEQ) {
				// equivalences along this path
				this.equivalenceSet.add(dest);
			}
			if (dest.equals(this)) {
				loop |= true;
				path.push(dest);
			} else {
				loop |= computeEQClash(dest, visited, loop, localEQ, path);
			}

			if (loop) {
				// add all nodes to eq set
				// path.push(dest);
				// this.equivalenceSet.addAll(path);
				// System.out.println("Loop found, path:"+this.renderStack(path));
			}
		}
		// System.out.print(renderStack(path));
		this.equivalenceSet.addAll(path);
		return loop;
	}

	public String renderStack(Stack<Vertex> s) {
		String st = "";
		int i = s.size() - 1;
		while (i >= 0) {
			Vertex o = s.get(i);
			i--;
			st += o.toString() + "; ";
		}
		return st;
	}

	public void addInEdge(Edge e) {
		this.inedges.add(e);
	}

	public void addOutEdge(Edge e) {
		this.outedges.add(e);
	}

	// @Override
	// public int hashCode() {
	// final int prime = 31;
	// int result = 1;
	// result = prime * result + ((f == null) ? 0 : f.hashCode());
	// return result;
	// }
	//
	// @Override
	// public boolean equals(Object obj) {
	// if (this == obj)
	// return true;
	// if (! (obj instanceof Vertex))
	// return false;
	// if (getClass() != obj.getClass())
	// return false;
	// Vertex other = (Vertex) obj;
	// if (f == null) {
	// if (other.f != null)
	// return false;
	// } else if (!f.equals(other.f))
	// return false;
	// return true;
	// }

}
